﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace AntrixServer
{
    public partial class Form1 : Form
    {
        private TcpListener server;
        private TcpClient client; 
        private Thread threadListener;
        private Int32 port;
        private IPAddress localAddr;
        private ArrayList cliThreads = new ArrayList();
        private Boolean portUsed = false;

        delegate void SetListCallback(String infoToAdd);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            listActivity.Items.Add("Welcome to Antrix!");
        }

        public void StopServer()
        {
            threadListener.Abort();
            server.Stop();
            AddToActivityList("Server Listener closed!");

            textPort.Enabled = true;
            textAddress.Enabled = true;
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }

        private void StartServer()
        {
            //Enable or disable all controls on the screen
            textPort.Enabled = false;
            textAddress.Enabled = false;
            btnStart.Enabled = false;
            btnStop.Enabled = true;

            //Create a new thread that listens for connections
            threadListener = new Thread(new ThreadStart(Listener));
            threadListener.Start();
        }

        private void Listener()
        {
            try
            {
                //Start the TcpListener and wait for a connection
                server = new TcpListener(localAddr, port);
                server.Start();

                //Add server.Start() to activity list
                AddToActivityList("Server listening at " + server.LocalEndpoint + ".");

                //Runs forever
                while (threadListener.IsAlive)
                {
                    //Client connecting, define thread for client
                    Thread threadClient = new Thread(new ParameterizedThreadStart(NewClient));

                    //Accept the client
                    client = server.AcceptTcpClient();

                    //Add client to activity list
                    String cliAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
                    String cliPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port.ToString();
                    AddToActivityList("New connection from " + cliAddress + ":" + cliPort + ".");

                    //Start the new thread , add thread to thread array, pass client to thread
                    threadClient.Start(client);
                }
            }
            catch (SocketException)
            {
                MessageBox.Show("Please make sure that the port is not already in use!");
                this.portUsed = true;
            }
        }

        private void NewClient(Object tcpClientObj)
        {
            //Add client thread to thread array
            cliThreads.Add(Thread.CurrentThread);

            //Define vars
            TcpClient tcpClient = (TcpClient)tcpClientObj;
            byte[] byteToSend;
            String messageToSend = "Welcome to Antrix! MOTD: " + textMOTD.Text;

            //Convert messageToSend from a String to a byte array so that it can be sent to the client
            byteToSend = Encoding.ASCII.GetBytes(messageToSend);

            //Send message to the client
            tcpClient.Client.Send(byteToSend);

            //Close the connection to the client
            tcpClient.Close();

            //Remove client thread from thread array
            cliThreads.Remove(Thread.CurrentThread);
        }

        public void AddToActivityList(String infoToAdd)
        {
            if (this.listActivity.InvokeRequired)
            {
                SetListCallback d = new SetListCallback(AddToActivityList);
                this.Invoke(d, new object[] { infoToAdd });
            } else {
                listActivity.Items.Add(infoToAdd);
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            try {
                //Get the ip address and port to listen on
                //Default: 0.0.0.0:31173 means to listen on all network cards on port 31173
                this.port = Int32.Parse(textPort.Text);
                this.localAddr = IPAddress.Parse(textAddress.Text);

                //Call the method to start the server
                StartServer();
            } catch(Exception) {
                //Makes sure that the IP and Port are not empty, alerts if they are
                MessageBox.Show("Please make sure that your IP and port are correct!");
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            StopServer();
        }
    }
}
